package com.cmc.cloud.cmclink.doc.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.map.MapUtil;
import com.baomidou.lock.annotation.Lock4j;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.cmc.cloud.cmclink.doc.api.document.emums.EmImTypeEnum;
import com.cmc.cloud.cmclink.doc.constants.errorconstant.VoyageBsaCbaErrorCodeConstants;
import com.cmc.cloud.cmclink.doc.constants.errorconstant.VoyageBsaErrorCodeConstants;
import com.cmc.cloud.cmclink.doc.entity.*;
import com.cmc.cloud.cmclink.doc.mapper.*;
import com.cmc.cloud.cmclink.doc.rpcservice.VoyScheduleService;
import com.cmc.cloud.cmclink.doc.service.VoyageBsaService;
import com.cmc.cloud.cmclink.doc.vo.voyagebsavo.*;
import com.cmc.cloud.cmclink.svl.api.base.enums.DateKindEnum;
import com.cmc.cloud.cmclink.svl.api.base.enums.SystemEnums;
import com.cmc.cloud.cmclink.svl.api.base.req.VoyQueryReqDTO;
import com.cmc.cloud.cmclink.svl.api.base.resp.VoyQueryRespDTO;
import com.cmes.framework.common.exception.util.ServiceExceptionUtil;
import com.cmes.framework.common.pojo.CommonResult;
import com.cmes.framework.common.pojo.PageResult;
import com.cmes.framework.mybatis.core.query.LambdaQueryWrapperX;
import com.cmes.framework.security.core.util.SecurityFrameworkUtils;
import com.cmes.platform.system.nuc.NucApi;
import com.cmes.platform.system.nuc.dto.UserProfileRespDto;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;

import javax.annotation.Resource;
import javax.validation.Valid;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;


/**
 * bsa （base space Allocation） 维护 Service 实现类
 *
 * @author 招商轮船-管理员
 */
@Service
@Validated
public class VoyageBsaServiceImpl implements VoyageBsaService {

    @Resource
    private VoyageBsaMapper voyageBsaMapper;

    @Resource
    private VoyageBsaHgMapper voyageBsaHgMapper;

    @Resource
    private VoyageBsaPodMapper voyageBsaPodMapper;

    @Resource
    private VoyScheduleService scheduleService;

    @Resource
    private VoyageBsaCbaMapper voyageBsaCbaMapper;

    @Resource
    private VoyageBsaCbaTemplateMapper voyageBsaCbaTemplateMapper;

    @Resource
    private VoyageBsaCbaDetailMapper voyageBsaCbaDetailMapper;

    @Resource
    private NucApi nucApi;

    @Override
    @Transactional(rollbackFor = Exception.class)
    @Lock4j(name = "voyageBsaUnique", keys = {"#createReqVO.getVesselCode", "#createReqVO.getVoyage"
            , "#createReqVO.getExImType", "#createReqVO.getPolCodes", "#createReqVO.getIsTemplate"})
    public void createVoyageBsa(VoyageBsaCreateReqVO createReqVO) {
        // 插入
        if (!createReqVO.getIsTemplate() && StringUtils.isEmpty(createReqVO.getVoyage())) {
            throw ServiceExceptionUtil.exception(VoyageBsaErrorCodeConstants.VOYAGE_BSA_VOYAGE_EMPTY);
        }
        validateUniqueExists(createReqVO, null);
        VoyageBsaDO voyageBsaDO = BeanUtil.copyProperties(createReqVO, VoyageBsaDO.class);
        voyageBsaMapper.insert(voyageBsaDO);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    @Lock4j(name = "voyageBsaUnique", keys = {"#updateReqVO.getVesselCode", "#updateReqVO.getVoyage"
            , "#updateReqVO.getExImType", "#updateReqVO.getPolCodes", "#updateReqVO.getIsTemplate"})
    public void updateVoyageBsa(VoyageBsaUpdateReqVO updateReqVO) {
        // 校验存在
        validateVoyageBsaExists(updateReqVO.getId());
        validateUniqueExists(updateReqVO, updateReqVO.getId());
        // 更新
        VoyageBsaDO updateObj = BeanUtil.copyProperties(updateReqVO, VoyageBsaDO.class);
        voyageBsaMapper.updateById(updateObj);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateOpenStatus(@Valid VoyageBsaStatusReqVO voyageBsaStatusReqVO) {
        VoyageBsaDO voyageBsaDO = voyageBsaMapper.selectById(voyageBsaStatusReqVO.getId());
        if (voyageBsaDO == null) {
            throw ServiceExceptionUtil.exception(VoyageBsaErrorCodeConstants.VOYAGE_BSA_NOT_EXISTS);
        }
        voyageBsaDO.setBookingOpenStatus(voyageBsaStatusReqVO.getBookingOpenStatus());
        Long loginUserId = SecurityFrameworkUtils.getLoginUserId();
        CommonResult<UserProfileRespDto> userProfile = null;
        try {
            userProfile = nucApi.getUserProfileById(loginUserId);
        } catch (Exception e) {
            e.printStackTrace();
        }
        if (userProfile == null || userProfile.getData() == null) {
            throw ServiceExceptionUtil.exception(VoyageBsaErrorCodeConstants.VOYAGE_BSA_CBA_USER_NOT_FOUND);
        }
        voyageBsaDO.setOpenCloseUser(userProfile.getData().getNickname());
        voyageBsaDO.setOpenCloseTime(LocalDateTime.now());
        voyageBsaDO.setUpdateTime(LocalDateTime.now());
        voyageBsaMapper.updateById(voyageBsaDO);
    }

    @Override
    public void deleteVoyageBsa(Long id) {
        // 校验存在
        validateVoyageBsaExists(id);
        // 删除
        voyageBsaMapper.deleteById(id);
    }

    private void validateUniqueExists(VoyageBsaBaseVO vo, Long id) {
        LambdaQueryWrapperX<VoyageBsaDO> queryWrapperX = new LambdaQueryWrapperX<VoyageBsaDO>()
                .eqIfPresent(VoyageBsaDO::getIsTemplate, vo.getIsTemplate())
                .eqIfPresent(VoyageBsaDO::getExImType, vo.getExImType())
                .eqIfPresent(VoyageBsaDO::getVesselCode, vo.getVesselCode())
                .eqIfPresent(VoyageBsaDO::getPolCodes, vo.getPolCodes())
                .eqIfPresent(VoyageBsaDO::getVoyage, vo.getVoyage());
        if (id != null) {
            queryWrapperX.ne(VoyageBsaDO::getId, id);
        }
        if (voyageBsaMapper.selectCount(queryWrapperX) != 0L) {
            if (vo.getIsTemplate()) {
                throw ServiceExceptionUtil.exception(VoyageBsaErrorCodeConstants.VOYAGE_BSA_TEMPLATE_EXISTED);
            }
            throw ServiceExceptionUtil.exception(VoyageBsaErrorCodeConstants.VOYAGE_BSA_EXISTED);
        }
    }

    private void validateVoyageBsaExists(Long id) {
        if (voyageBsaMapper.selectById(id) == null) {
            throw ServiceExceptionUtil.exception(VoyageBsaErrorCodeConstants.VOYAGE_BSA_NOT_EXISTS);
        }
    }

    @Override
    public VoyageBsaDO getVoyageBsa(Long id) {
        return voyageBsaMapper.selectById(id);
    }

    @Override
    public List<VoyageBsaDO> getVoyageBsaList(Collection<Long> ids) {
        return voyageBsaMapper.selectBatchIds(ids);
    }

    @Override
    public PageResult<VoyageBsaRespVO> getVoyageBsaPage(VoyageBsaPageReqVO reqVO) {
        VoyageBsaExportReqVO voyageBsaExportReqVO = BeanUtil.copyProperties(reqVO, VoyageBsaExportReqVO.class);
        LambdaQueryWrapperX<VoyageBsaDO> wrapperX;
        Map<String, List<VoyQueryRespDTO>> dataMap = MapUtil.newHashMap(8);
        if (!reqVO.getIsTemplate()) {
            wrapperX = getWrapperX(voyageBsaExportReqVO, dataMap);
        } else {
            wrapperX = getWrapperX(voyageBsaExportReqVO, null);
        }
        PageResult<VoyageBsaDO> pageResult = voyageBsaMapper.selectPage(reqVO, wrapperX);
        List<VoyageBsaRespVO> voyageBsaRespVos = BeanUtil.copyToList(pageResult.getList(), VoyageBsaRespVO.class);
        PageResult<VoyageBsaRespVO> result = new PageResult<>(voyageBsaRespVos, pageResult.getTotal());
        if (CollectionUtil.isNotEmpty(voyageBsaRespVos) && !reqVO.getIsTemplate() && EmImTypeEnum.EXPORT.getValue().equals(reqVO.getExImType())) {
            voyageBsaRespVos.forEach(entity -> {
                List<VoyQueryRespDTO> voyQueryRespDTOList = dataMap.get(entity.getLaneCode() + "_" + entity.getPolCodes() + "_" + entity.getVesselCode() + "_" + entity.getVoyage());
                if (CollectionUtil.isNotEmpty(voyQueryRespDTOList) && voyQueryRespDTOList.get(0) != null) {
                    VoyQueryRespDTO voyQueryRespDTO = voyQueryRespDTOList.get(0);
                    entity.setEtu(StringUtils.isNotEmpty(voyQueryRespDTO.getEtu()) ? voyQueryRespDTO.getEtu() : voyQueryRespDTO.getPtu());
                }
            });
        }
        return result;
    }

    @Override
    public List<VoyageBsaRespVO> queryVoyageBsa(VoyageBsaBaseQueryVo bsaBaseQueryVo) {
        //默认查询前50条
        Page<VoyageBsaDO> pageParam = new Page<>(1, 50);
        Page<VoyageBsaDO> voyageBsaDoPage = voyageBsaMapper.selectPage(pageParam, new LambdaQueryWrapperX<VoyageBsaDO>()
                .eq(VoyageBsaDO::getIsTemplate, bsaBaseQueryVo.getIsTemplate())
                .eq(VoyageBsaDO::getExImType, bsaBaseQueryVo.getExImType())
                .eq(VoyageBsaDO::getLaneCode, bsaBaseQueryVo.getLaneCode())
                .eqIfPresent(VoyageBsaDO::getPolCodes, bsaBaseQueryVo.getPolCodes())
                .eqIfPresent(VoyageBsaDO::getVesselCode, bsaBaseQueryVo.getVesselCode())
                .eqIfPresent(VoyageBsaDO::getVoyage, bsaBaseQueryVo.getVoyage())
                .orderByDesc(VoyageBsaDO::getCreateTime));
        return BeanUtil.copyToList(voyageBsaDoPage.getRecords(), VoyageBsaRespVO.class);
    }

    @Override
    public List<VoyageBsaExportVO> getExportList(VoyageBsaExportReqVO voyageBsaExportReqVO) {
        Map<String, List<VoyQueryRespDTO>> dataMap = MapUtil.newHashMap();
        LambdaQueryWrapperX<VoyageBsaDO> wrapperX = getWrapperX(voyageBsaExportReqVO, dataMap);
        List<VoyageBsaDO> voyageBsaDos = voyageBsaMapper.selectList(wrapperX);
        List<VoyageBsaExportVO> voyageBsaExportVos = BeanUtil.copyToList(voyageBsaDos, VoyageBsaExportVO.class);
        if (CollectionUtil.isNotEmpty(voyageBsaExportVos)) {
            voyageBsaExportVos.forEach(entity -> {
                List<VoyQueryRespDTO> voyQueryRespDTOList = dataMap.get(entity.getLaneCode() + "_" + entity.getPolCodes() + "_" + entity.getVesselCode() + "_" + entity.getVoyage());
                if (CollectionUtil.isNotEmpty(voyQueryRespDTOList) && voyQueryRespDTOList.get(0) != null) {
                    entity.setEtu(voyQueryRespDTOList.get(0).getEtu());
                }
            });
        }
        return voyageBsaExportVos;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void createFromTemplate(VoyageTemplateReqVO templateReqVO) {
        VoyageBsaDO originalData = new VoyageBsaDO();
        List<VoyageBsaDO> existBsa = getExistBsa(templateReqVO, originalData);
        Map<String, Long> map = existBsa.stream().collect(Collectors.toMap(VoyageBsaDO::getVoyage, VoyageBsaDO::getId));
        List<VoyageBsaDO> newVoyageBsas = new ArrayList<>();
        templateReqVO.getVoyages().forEach(entity -> {
            VoyageBsaDO voyageBsaDO = BeanUtil.copyProperties(originalData, VoyageBsaDO.class, "createTime", "updateTime", "creator", "updater");
            voyageBsaDO.setIsTemplate(false);
            voyageBsaDO.setVoyage(entity);
            voyageBsaDO.setId(null);
            if (CollectionUtil.isNotEmpty(map)) {
                if (map.containsKey(entity)) {
                    voyageBsaDO.setId(map.get(entity));
                }
            }
            newVoyageBsas.add(voyageBsaDO);
        });
        voyageBsaMapper.saveOrUpdateBatch(newVoyageBsas);
        Set<Long> bsaIds = newVoyageBsas.stream().map(p -> p.getId()).collect(Collectors.toSet());
        voyageBsaHgMapper.delete(new LambdaQueryWrapperX<VoyageBsaHgDO>().inIfPresent(VoyageBsaHgDO::getVoyageBsaId, bsaIds));
        voyageBsaPodMapper.delete(new LambdaQueryWrapperX<VoyageBsaPodDO>().inIfPresent(VoyageBsaPodDO::getVoyageBsaId, bsaIds));
        //绑定高箱信息
        List<VoyageBsaHgDO> voyageBsaHgDOList = voyageBsaHgMapper.selectList(new LambdaQueryWrapperX<VoyageBsaHgDO>().eq(VoyageBsaHgDO::getVoyageBsaId, templateReqVO.getTemplateId()));
        if (CollectionUtil.isNotEmpty(voyageBsaHgDOList)) {
            List<VoyageBsaHgDO> voyageBsaHgDoArrayList = new ArrayList<>();
            for (Long bsaId : bsaIds) {
                voyageBsaHgDOList.forEach(entity -> {
                    VoyageBsaHgDO voyageBsaHgDO = BeanUtil.copyProperties(entity, VoyageBsaHgDO.class, "createTime", "updateTime", "creator", "updater");
                    voyageBsaHgDO.setId(null);
                    voyageBsaHgDO.setVoyageBsaId(bsaId);
                    voyageBsaHgDoArrayList.add(voyageBsaHgDO);
                });
            }
            voyageBsaHgMapper.insertBatch(voyageBsaHgDoArrayList);
        }
        //绑定目的港舱位分配信息
        List<VoyageBsaPodDO> bsaPodDOList = voyageBsaPodMapper.selectList(new LambdaQueryWrapperX<VoyageBsaPodDO>().eq(VoyageBsaPodDO::getVoyageBsaId, templateReqVO.getTemplateId()));
        if (CollectionUtil.isNotEmpty(bsaPodDOList)) {
            List<VoyageBsaPodDO> voyageBsaPodDOList = new ArrayList<>();
            for (Long bsaId : bsaIds) {
                bsaPodDOList.forEach(entity -> {
                    VoyageBsaPodDO voyageBsaPodDO = BeanUtil.copyProperties(entity, VoyageBsaPodDO.class, "createTime", "updateTime", "creator", "updater");
                    voyageBsaPodDO.setId(null);
                    voyageBsaPodDO.setVoyageBsaId(bsaId);
                    voyageBsaPodDOList.add(voyageBsaPodDO);
                });
            }
            voyageBsaPodMapper.insertBatch(voyageBsaPodDOList);
        }
    }

    @Override
    public List<String> getExistVoyages(VoyageTemplateReqVO templateReqVO) {
        List<String> voyages = new ArrayList<>();
        List<VoyageBsaDO> voyageBsaDOList = getExistBsa(templateReqVO, null);
        if (CollectionUtil.isNotEmpty(voyageBsaDOList)) {
            voyages = voyageBsaDOList.stream().map(VoyageBsaDO::getVoyage).collect(Collectors.toList());
        }
        return voyages;
    }

    private List<VoyageBsaDO> getExistBsa(VoyageTemplateReqVO templateReqVO, VoyageBsaDO templateBsa) {
        VoyageBsaDO originalData = voyageBsaMapper.selectById(templateReqVO.getTemplateId());
        if (originalData == null) {
            throw ServiceExceptionUtil.exception(VoyageBsaErrorCodeConstants.VOYAGE_BSA_TEMPLATE_NOT_EXISTS);
        }
        if (templateBsa != null) {
            BeanUtil.copyProperties(originalData, templateBsa);
        }
        List<VoyageBsaDO> voyageBsaDos = voyageBsaMapper.selectList(new LambdaQueryWrapperX<VoyageBsaDO>()
                .eq(VoyageBsaDO::getIsTemplate, false)
                .eq(VoyageBsaDO::getPolCodes, originalData.getPolCodes())
                .eq(VoyageBsaDO::getLaneCode, originalData.getLaneCode())
                .eq(VoyageBsaDO::getVesselCode, originalData.getVesselCode())
                .inIfPresent(VoyageBsaDO::getVoyage, templateReqVO.getVoyages()));
        return voyageBsaDos;
    }

    private LambdaQueryWrapperX<VoyageBsaDO> getWrapperX(VoyageBsaExportReqVO reqVO, Map<String, List<VoyQueryRespDTO>> dataMap) {
        LambdaQueryWrapperX<VoyageBsaDO> queryWrapperX = new LambdaQueryWrapperX<>();
        queryWrapperX.eq(VoyageBsaDO::getExImType, reqVO.getExImType())
                .eq(VoyageBsaDO::getIsTemplate, reqVO.getIsTemplate())
                .eqIfPresent(VoyageBsaDO::getLaneCode, reqVO.getLaneCode())
                .likeIfPresent(VoyageBsaDO::getPolCodes, reqVO.getPolCodes())
                .eqIfPresent(VoyageBsaDO::getVesselCode, reqVO.getVesselCode())
                .eqIfPresent(VoyageBsaDO::getVoyage, reqVO.getVoyage());
        if ((!reqVO.getIsTemplate())) {
            if (StringUtils.isEmpty(reqVO.getStartTime()) && StringUtils.isEmpty(reqVO.getEndTime())) {
                throw ServiceExceptionUtil.exception(VoyageBsaErrorCodeConstants.VOYAGE_BSA_TIME_EMPTY);
            }
            if (StringUtils.isEmpty(reqVO.getLaneCode())) {
                throw ServiceExceptionUtil.exception(VoyageBsaErrorCodeConstants.VOYAGE_BSA_LANE_EMPTY);
            }
            VoyQueryReqDTO voyQueryReqDTO = new VoyQueryReqDTO();
            voyQueryReqDTO.setSystemNumber(SystemEnums.DOC.getSystemNumber());
            voyQueryReqDTO.setDateKind(DateKindEnum.SEARCH_PERFORM.getLabel());
            voyQueryReqDTO.setDateType("ETU");
            voyQueryReqDTO.setLaneCode(reqVO.getLaneCode());
            //时间跨度范围不可超过一个月
            if (StringUtils.isNotEmpty(reqVO.getStartTime())) {
                voyQueryReqDTO.setStartDate(reqVO.getStartTime());
            }
            if (StringUtils.isNotEmpty(reqVO.getEndTime())) {
                voyQueryReqDTO.setEndDate(reqVO.getEndTime());
            }
            List<VoyQueryRespDTO> checkedData = scheduleService.listByCondition(voyQueryReqDTO);
            if (CollectionUtil.isNotEmpty(checkedData)) {
                if (dataMap != null && EmImTypeEnum.EXPORT.getValue().equals(reqVO.getExImType())) {
                    dataMap.putAll(checkedData.stream().collect(Collectors.groupingBy(
                            vo -> vo.getLaneCode() + "_" + vo.getPortCode() + "_" + vo.getVesselCode() + "_" + (EmImTypeEnum.EXPORT.getValue().equals(reqVO.getExImType()) ? vo.getExVoy() : vo.getImVoy()))));
                }
                Set<String> vesselCodes = checkedData.stream().map(VoyQueryRespDTO::getVesselCode).collect(Collectors.toSet());
                Set<String> laneCodes = checkedData.stream().map(VoyQueryRespDTO::getLaneCode).collect(Collectors.toSet());
                queryWrapperX.inIfPresent(VoyageBsaDO::getVesselCode, vesselCodes);
                queryWrapperX.inIfPresent(VoyageBsaDO::getLaneCode, laneCodes);
                if (!reqVO.getIsTemplate()) {
                    Set<String> voyages;
                    if (EmImTypeEnum.EXPORT.getValue().equals(reqVO.getExImType())) {
                        voyages = checkedData.stream().map(VoyQueryRespDTO::getExVoy).collect(Collectors.toSet());
                    } else {
                        voyages = checkedData.stream().map(VoyQueryRespDTO::getImVoy).collect(Collectors.toSet());
                    }
                    queryWrapperX.inIfPresent(VoyageBsaDO::getVoyage, voyages);
                }
            } else {
                return new LambdaQueryWrapperX<VoyageBsaDO>().eq(VoyageBsaDO::getExImType, "NOT_EXIST");
            }
        }
        return queryWrapperX;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void copyFromHistory(VoyageBsaHistoryVO historyVo) {
        VoyageBsaDO originalData = voyageBsaMapper.selectById(historyVo.getOriginalId());
        if (originalData == null) {
            throw ServiceExceptionUtil.exception(VoyageBsaErrorCodeConstants.VOYAGE_BSA_TEMPLATE_NOT_EXISTS);
        }
        if (!originalData.getIsTemplate() && StringUtils.isEmpty(historyVo.getVoyage())) {
            throw ServiceExceptionUtil.exception(VoyageBsaErrorCodeConstants.VOYAGE_BSA_VOYAGE_EMPTY);
        }
        VoyageBsaDO voyageBsaDO = new VoyageBsaDO();
        BeanUtil.copyProperties(originalData, voyageBsaDO, "createTime", "updateTime", "creator", "updater");
        voyageBsaDO.setId(null);
        BeanUtil.copyProperties(historyVo, voyageBsaDO);
        voyageBsaMapper.insert(voyageBsaDO);
        //绑定高箱信息
        List<VoyageBsaHgDO> bsaHgDOList = voyageBsaHgMapper.selectList(new LambdaQueryWrapperX<VoyageBsaHgDO>().eq(VoyageBsaHgDO::getVoyageBsaId, originalData.getId()));
        if (CollectionUtil.isNotEmpty(bsaHgDOList)) {
            List<VoyageBsaHgDO> voyageBsaHgDOList = new ArrayList<>();
            bsaHgDOList.forEach(entity -> {
                VoyageBsaHgDO voyageBsaHgDO = BeanUtil.copyProperties(entity, VoyageBsaHgDO.class, "createTime", "updateTime", "creator", "updater");
                voyageBsaHgDO.setId(null);
                voyageBsaHgDO.setVoyageBsaId(voyageBsaDO.getId());
                voyageBsaHgDOList.add(voyageBsaHgDO);
            });
            voyageBsaHgMapper.insertBatch(voyageBsaHgDOList);
        }
        //绑定目的港舱位分配信息
        List<VoyageBsaPodDO> bsaPodDOList = voyageBsaPodMapper.selectList(new LambdaQueryWrapperX<VoyageBsaPodDO>().eq(VoyageBsaPodDO::getVoyageBsaId, originalData.getId()));
        if (CollectionUtil.isNotEmpty(bsaPodDOList)) {
            List<VoyageBsaPodDO> voyageBsaPodDOList = new ArrayList<>();
            bsaPodDOList.forEach(entity -> {
                VoyageBsaPodDO voyageBsaPodDO = BeanUtil.copyProperties(entity, VoyageBsaPodDO.class, "createTime", "updateTime", "creator", "updater");
                voyageBsaPodDO.setId(null);
                voyageBsaPodDO.setVoyageBsaId(voyageBsaDO.getId());
                voyageBsaPodDOList.add(voyageBsaPodDO);
            });
            voyageBsaPodMapper.insertBatch(voyageBsaPodDOList);
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void copyFromHistoryCba(VoyageBsaHistoryVO historyVo) {
        List<VoyageBsaCbaDO> voyageBsaCbaDos = voyageBsaCbaMapper.selectList(new LambdaQueryWrapper<VoyageBsaCbaDO>().eq(VoyageBsaCbaDO::getVoyageBsaId, historyVo.getOriginalId()));
        if (CollectionUtil.isEmpty(voyageBsaCbaDos)) {
            throw ServiceExceptionUtil.exception(VoyageBsaErrorCodeConstants.VOYAGE_BSA_CBA_NOT_EXIST);
        }
        VoyageBsaBaseVO voyageBsaBaseVO = BeanUtil.copyProperties(historyVo, VoyageBsaBaseVO.class);
        voyageBsaBaseVO.setIsTemplate(false);
        voyageBsaBaseVO.setExImType(EmImTypeEnum.EXPORT.getValue());
        if (this.assertBsaCbaExist(voyageBsaBaseVO)) {
            //覆盖操作 删除原有绑定
            voyageBsaCbaMapper.delete(new LambdaQueryWrapper<VoyageBsaCbaDO>().eq(VoyageBsaCbaDO::getVoyageBsaId, historyVo.getTargetId()));
        }
        //新增操作
        VoyageBsaDO voyageBsaDO = voyageBsaMapper.selectById(historyVo.getTargetId());
        if(voyageBsaDO==null){
            throw ServiceExceptionUtil.exception(VoyageBsaErrorCodeConstants.VOYAGE_BSA_NOT_EXISTS);
        }
        if(voyageBsaDO.getBsaTeu().compareTo(voyageBsaCbaDos.stream().mapToInt(VoyageBsaCbaDO::getAllocationSpace).sum())<0){
            throw ServiceExceptionUtil.exception(VoyageBsaCbaErrorCodeConstants.VOYAGE_BSA_CAB_TEU_NOT_EQUAL);
        }
        if(voyageBsaDO.getRfUnit().compareTo(voyageBsaCbaDos.stream().mapToInt(VoyageBsaCbaDO::getRfUnit).sum())<0){
            throw ServiceExceptionUtil.exception(VoyageBsaCbaErrorCodeConstants.VOYAGE_BSA_CAB_TEU_NOT_EQUAL);
        }
        List<VoyageBsaCbaDO> newCbaDos = new ArrayList<>();
        voyageBsaCbaDos.forEach(entity -> {
            VoyageBsaCbaDO voyageBsaCbaDO = BeanUtil.copyProperties(entity, VoyageBsaCbaDO.class, "id", "createTime", "updateTime", "creator", "updater");
            voyageBsaCbaDO.setRemainRfUnit(voyageBsaCbaDO.getRfUnit());
            voyageBsaCbaDO.setRemainAllocationSpace(voyageBsaCbaDO.getAllocationSpace());
            voyageBsaCbaDO.setVoyageBsaId(historyVo.getTargetId());
            newCbaDos.add(voyageBsaCbaDO);
        });
        voyageBsaCbaMapper.insertBatch(newCbaDos);
        Set<Long> collect = voyageBsaCbaDos.stream().map(vo -> vo.getId()).collect(Collectors.toSet());
        //原 cba挂载的表达式信息
        List<VoyageBsaCbaDetailDO> detailDOList = voyageBsaCbaDetailMapper.selectList(new LambdaQueryWrapperX<VoyageBsaCbaDetailDO>().inIfPresent(VoyageBsaCbaDetailDO::getVoyageBsaCbaId, collect));
        if (CollectionUtil.isNotEmpty(detailDOList)) {
            Map<String, Long> cbaNewMap = newCbaDos.stream()
                    .collect(Collectors.toMap(
                            p -> p.getAllocationSpace() + "_" + p.getSpaceTypeCode(),
                            VoyageBsaCbaDO::getId,
                            (existing, replacement) -> existing
                            // 处理键冲突的策略
                    ));
            Map<Long, Long> idMap = new HashMap<>(16);
            voyageBsaCbaDos.stream().forEach(a -> {
                idMap.put(a.getId(), cbaNewMap.get(a.getAllocationSpace() + "_" + a.getSpaceTypeCode()));
            });
            List<VoyageBsaCbaDetailDO> newCbaDetailList = CollectionUtil.newArrayList();

            for (VoyageBsaCbaDetailDO entity : detailDOList) {
                VoyageBsaCbaDetailDO voyageBsaCbaDetailDO = new VoyageBsaCbaDetailDO();
                voyageBsaCbaDetailDO.setJsonString(entity.getJsonString());
                voyageBsaCbaDetailDO.setVoyageBsaCbaId(idMap.get(entity.getVoyageBsaCbaId()));
                newCbaDetailList.add(voyageBsaCbaDetailDO);
            }
            voyageBsaCbaDetailMapper.insertBatch(newCbaDetailList);
        }
    }

    @Override
    public Boolean assertBsaCbaExist(VoyageBsaBaseVO voyageBsaBaseVO) {
        List<VoyageBsaDO> bsaFromPersonInfo = voyageBsaMapper.getBsaFromPersonInfo(voyageBsaBaseVO);
        //存在 bsaCba 信息
        //不存在 bsaCba 信息
        return CollectionUtil.isNotEmpty(bsaFromPersonInfo);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void collectBsaTemplate(Long bsaId) {
        VoyageBsaDO originalData = voyageBsaMapper.selectById(bsaId);
        if (originalData == null) {
            throw ServiceExceptionUtil.exception(VoyageBsaErrorCodeConstants.VOYAGE_BSA_TEMPLATE_NOT_EXISTS);
        }
        VoyageBsaDO voyageBsaDO = BeanUtil.copyProperties(originalData, VoyageBsaDO.class, "createTime", "updateTime", "creator", "updater");
        voyageBsaDO.setId(null);
        voyageBsaDO.setIsTemplate(true);
        voyageBsaDO.setVoyage("");
        validateUniqueExists(BeanUtil.copyProperties(voyageBsaDO, VoyageBsaBaseVO.class), null);
        voyageBsaMapper.insert(voyageBsaDO);
        //绑定高箱信息
        List<VoyageBsaHgDO> bsaHgDOList = voyageBsaHgMapper.selectList(new LambdaQueryWrapperX<VoyageBsaHgDO>().eq(VoyageBsaHgDO::getVoyageBsaId, originalData.getId()));
        if (CollectionUtil.isNotEmpty(bsaHgDOList)) {
            List<VoyageBsaHgDO> voyageBsaHgDOList = new ArrayList<>();
            bsaHgDOList.forEach(entity -> {
                VoyageBsaHgDO voyageBsaHgDO = BeanUtil.copyProperties(entity, VoyageBsaHgDO.class, "createTime", "updateTime", "creator", "updater");
                voyageBsaHgDO.setId(null);
                voyageBsaHgDO.setVoyageBsaId(voyageBsaDO.getId());
                voyageBsaHgDOList.add(voyageBsaHgDO);
            });
            voyageBsaHgMapper.insertBatch(voyageBsaHgDOList);
        }
        //绑定目的港舱位分配信息
        List<VoyageBsaPodDO> voyageBsaPodDOList = voyageBsaPodMapper.selectList(new LambdaQueryWrapperX<VoyageBsaPodDO>().eq(VoyageBsaPodDO::getVoyageBsaId, originalData.getId()));
        if (CollectionUtil.isNotEmpty(voyageBsaPodDOList)) {
            List<VoyageBsaPodDO> bsaPodDOList = new ArrayList<>();
            voyageBsaPodDOList.forEach(entity -> {
                VoyageBsaPodDO voyageBsaPodDO = BeanUtil.copyProperties(entity, VoyageBsaPodDO.class, "createTime", "updateTime", "creator", "updater");
                voyageBsaPodDO.setId(null);
                voyageBsaPodDO.setVoyageBsaId(voyageBsaDO.getId());
                bsaPodDOList.add(voyageBsaPodDO);
            });
            voyageBsaPodMapper.insertBatch(bsaPodDOList);
        }
    }


    public VoyageBsaDO findVoyageBsa(String vesselCode, String voyage,String portCode, String exImType) {
        VoyageBsaDO voyageLock = voyageBsaMapper.selectOne(
                new LambdaQueryWrapper<>(VoyageBsaDO.class)
                        .eq(VoyageBsaDO::getVesselCode, vesselCode)
                        .eq(VoyageBsaDO::getVoyage, voyage)
                        .like(VoyageBsaDO::getPolCodes, portCode)
                        .eq(VoyageBsaDO::getExImType, exImType)
                        .last("limit 1")
        );
        return voyageLock;
    }
}
